import { BuilderHTMLElement, FarrisDesignBaseComponent } from '@farris/designer-element';
import { DesignerEnvType, DesignViewModel, FormBasicService, FormBinding, RefreshFormService, SchemaService } from '@farris/designer-services';
import { RowNode } from '@farris/ui-treetable';
import { FormPropertyChangeObject } from '../../../../../entity/property-change-entity';
import { DgControl } from '../../../.././../utils/dg-control';
import { InputsContextMenuService } from '../context-menu/context-menu.manager';
import { DesignViewModelService, DomService, FormBindingType, FormSchemaEntityField$Type } from '@farris/designer-services';
import { ComponentFactoryResolver, Injector } from '@angular/core';
import { BsModalService } from '@farris/ui-modal';
import { SaveAsTemplateEditorComponent } from '@farris/designer-devkit';
import { cloneDeep } from 'lodash-es';

export default class FarrisDesignField extends FarrisDesignBaseComponent {
    /** 控件当前运行环境 */
    envType: DesignerEnvType;
    /** 控件绑定字段或变量是否有效 */
    isValidBinding = true;

    constructor(component: any, options: any) {
        super(component, options);

        // 组件所属分类为“输入类”
        this.category = 'input';

        const serviceHost = this.options.designerHost;
        const formBasicService = serviceHost.getService('FormBasicService') as FormBasicService;
        if (formBasicService) {
            this.envType = formBasicService.envType;
        }


        if (this.envType === DesignerEnvType.noCode) {
            this.addSaveAsCustomToolbarConfig();
        }
    }

    /**
     * 获取组件级样式
     */
    getClassName(): string {
        let clsName = super.getClassName();
        if (!this.parent) {
            return clsName;
        }


        // 获取父级Form组件上配置的【控件标签与输入框在一行展示】属性，将样式追加到每个输入控件上。这样是为了防止拖拽过程中的元素不受此属性控制，出现掉出蓝框的现象。
        if (this.parent.type === DgControl.Form.type) {
            clsName += this.checkControlsInLine(this.parent.component);
            return clsName;
        }
        if (this.parent.type === DgControl.FieldSet.type && this.parent.parent && this.parent.parent.type === DgControl.Form.type) {
            clsName += this.checkControlsInLine(this.parent.parent.component);
            return clsName;
        }
        // 获取父级ResponseLayoutItem组件上配置的【控件标签与输入框在一行展示】属性，将样式追加到每个输入控件上。这样是为了防止拖拽过程中的元素不受此属性控制，出现掉出蓝框的现象。
        if (this.parent.type === DgControl.ResponseLayoutItem.type) {
            const parentCmpSchema = this.parent.component;
            if (parentCmpSchema && parentCmpSchema.appearance && parentCmpSchema.appearance.class && parentCmpSchema.appearance.class.includes('farris-form-controls-inline')) {
                clsName += ' farris-form-controls-inline';
            }
            return clsName;
        }
        // table内的可输入控件，需要增加样式
        if (this.component.showInTable) {
            clsName += ' d-block h-100 inputInTable';
        }
        return clsName;
    }

    /**
     * 判断控件样式中是否需要追加farris-form-controls-inline
     * @param formNode 父级Form控件schema数据
     */
    private checkControlsInLine(formNode: any) {

        // 启用国际化适配：根据当前语言来判断
        if (formNode.formAutoIntl) {
            const isZhCHSLanguage = localStorage && localStorage.getItem('languageCode') || 'zh-CHS';
            return isZhCHSLanguage === 'zh-CHS' ? ' farris-form-controls-inline' : '';
        }

        // 未启用国际化适配：根据controlsInline属性来判断
        return formNode.controlsInline ? ' farris-form-controls-inline' : '';
    }
    /**
     * 渲染输入类控件，将label提取出来
     * @param element 输入框部分的html
     */
    render(element: any, showLabel: boolean = true): string {
        this.checkBindingFieldValidation();

        return super.render(this.renderTemplate('Field', {
            element,
            isValidBinding: this.isValidBinding,
            showLabel
        }));
    }


    attach(element: BuilderHTMLElement): Promise<any> {
        const superAttach: any = super.attach(element);

        if (this.element.className && this.element.className.includes('dgComponentSelected')) {
            this.registerLableSpanContentEditable();
        }

        return superAttach;
    }
    /**
     * 监听属性面板的属性变更事件，并触发模板重绘。默认监听样式类属性
     * @param changeObject 属性变更集
     * @param propertyIDs 需要额外监听变更的属性id列表
     */
    onPropertyChanged(changeObject: FormPropertyChangeObject, propertyIDs?: string[]): void {
        let dynamicPropertyIDs = ['title', 'enableTitleTips', 'titleTipsTemplate', 'appearance.class', 'appearance.style', 'size.width', 'size.height', 'require', 'placeHolder', 'col', 'labelAutoWidth'];
        if (propertyIDs) {
            dynamicPropertyIDs = dynamicPropertyIDs.concat(propertyIDs);
        }

        const propertyPath = changeObject.propertyPath ? changeObject.propertyPath + '.' : '';
        if (dynamicPropertyIDs.includes(propertyPath + changeObject.propertyID)) {
            this.triggerRedraw();
        }

        // 绑定无效字段的控件，切换绑定后，需要重绘模板并更新属性面板，所以这里触发了设计器上当前控件的刷新
        if (!this.isValidBinding && changeObject.propertyID === 'binding') {
            const refreshFormService = this.options.designerHost.getService('RefreshFormService');
            refreshFormService.refreshFormDesigner.next(this.id);
        }
    }


    /**
     * 删除控件：同步移除视图模型配置数据
     */
    onRemoveComponent() {
        const bindingField = this.component.binding && this.component.binding.field;
        // 若有绑定关系，在删除控件时需要同步删除ViewModel.fields中的记录
        if (!bindingField) {
            return;
        }
        const serviceHost = this.options.designerHost;
        const dgViewModelService = serviceHost.getService('DesignViewModelService');
        const dgViewModel = dgViewModelService.getDgViewModel(this.viewModelId);
        const schemaService = serviceHost.getService('SchemaService') as SchemaService;

        if (dgViewModel) {
            dgViewModel.removeField([bindingField]);
        }

        // 移除schema中的字段--零代码场景
        schemaService.removeSchemaField([bindingField]);

        // 若输入控件是放在布局容器中的，删除控件后需要更新容器的样式
        if (this.parent && this.parent.type === DgControl.ResponseLayoutItem.type && this.parent.removeFormClassFromResponseLayoutItem) {
            this.parent.removeFormClassFromResponseLayoutItem();
        }

        // 若绑定字段配置了表达式，需要删除表达式
        const domService = serviceHost.getService('DomService') as DomService;
        if (domService.expressions && domService.expressions.length) {
            const expFieldIndex = domService.expressions.findIndex(e => e.fieldId === bindingField);
            if (expFieldIndex > -1) {
                domService.expressions.splice(expFieldIndex, 1);
            }

        }
    }

    onMoveComponent() {
        // 需要考虑控件移入移出分组、移出到其他Component的场景 
    }


    /**
     * 组装输入类右键菜单
     * @param rowNode 组件在控件树上对应的行数据
     */
    resolveContextMenuConfig(rowNode: RowNode) {
        const menuManager = new InputsContextMenuService(this);
        return menuManager.setContextMenuConfig();
    }
    /**
     * 检查控件的绑定是否有效
     */
    private checkBindingFieldValidation() {
        this.isValidBinding = true;
        if (!this.component.binding || !this.component.binding.field) {
            return;
        }
        switch (this.component.binding.type) {
            case FormBindingType.Form: {
                this.isValidBinding = this.checkBindingFormFieldValidation();
                break;
            }
            case FormBindingType.Variable: {
                this.isValidBinding = this.checkBindingVariableFieldValidation();
            }
        }

    }

    private checkBindingFormFieldValidation() {
        const dgVMService = this.options.designerHost.getService('DesignViewModelService') as DesignViewModelService;
        const dgViewModel = dgVMService.getDgViewModel(this.viewModelId);
        const dgVMField = dgViewModel.fields.find(f => f.id === this.component.binding.field);

        // schema中已移除的字段
        if (!dgVMField) {
            return false;
        }
        // 在schema中类型已发生变更的字段，例如由普通文本字段改成了关联字段
        if (dgVMField.$type !== FormSchemaEntityField$Type.SimpleField) {
            return false;
        }

        return true;
    }

    private checkBindingVariableFieldValidation() {
        const domService = this.options.designerHost.getService('DomService') as DomService;
        const bindingVarible = domService.getVariableById(this.component.binding.field);

        // vm中已移除的变量
        if (!bindingVarible) {
            return false;
        }

        return true;
    }

    /**
     * 零代码：支持输入控件另存为模板
     */
    private addSaveAsCustomToolbarConfig() {
        if (!this.customToolbarConfigs) {
            this.customToolbarConfigs = [];
        }
        // 目前只支持绑定简单类字段的控件
        if (this.component.binding && this.component.binding.path && !this.component.binding.path.includes('_')) {
            this.customToolbarConfigs.push(
                {
                    id: 'saveAsTemplate',
                    title: '另存为模板',
                    icon: 'f-icon f-icon-save',
                    click: (e) => {
                        e.stopPropagation();
                        this.showSaveAsTemplateModal();
                    }
                });
        }

    }

    /**
     * 零代码：弹出另存为模板的窗口
     */
    private showSaveAsTemplateModal() {
        // 动态创建相关的服务需要从designerHost中获取
        const serviceHost = this.options.designerHost;
        const resolver = serviceHost.getService('ComponentFactoryResolver') as ComponentFactoryResolver;
        const injector = serviceHost.getService('Injector') as Injector;
        const modalService = serviceHost.getService('ModalService') as BsModalService;

        const compFactory = resolver.resolveComponentFactory(SaveAsTemplateEditorComponent);
        const compRef = compFactory.create(injector);
        const modalConfig = compRef.instance.modalConfig as any;
        modalConfig.height = 200;
        modalConfig.width = 450;
        modalConfig.buttons = compRef.instance.modalFooter;


        const templateDom = cloneDeep(this.component);

        compRef.instance.editorParams = {
            controlCategory: 'input',
            controlTitle: this.component.title || '',
            controlDom: templateDom,
            viewModelId: this.viewModelId
        }

        const modalPanel = modalService.show(compRef, modalConfig);
        compRef.instance.closeModal.subscribe(() => {
            modalPanel.close();
        });
        compRef.instance.submitModal.subscribe(() => {
            modalPanel.close();

            // 刷新控件工具箱
            const refreshFormService = this.options.designerHost.getService('RefreshFormService') as RefreshFormService;
            if (refreshFormService && refreshFormService.refreshControlBox) {
                refreshFormService.refreshControlBox.next();
            }
        });
    }

    /**
     * 点击输入类控件后，启用模板中标签区域的编辑
     * @param e 
     * @returns 
     */
    afterComponentClicked(e?: PointerEvent): void {
        this.registerLableSpanContentEditable();
    }

    /**
     * 取消点击输入控件后，移除标签区域的编辑特性
     * @param e 
     * @returns 
     */
    afterComponentCancelClicked(e?: PointerEvent): void {
        if (!this.element) {
            return;
        }
        const labelSpanEle = this.element.querySelector('.farris-label-text');
        if (!labelSpanEle) {
            return;
        }
        labelSpanEle.removeAttribute('contenteditable');

        this.removeEventListener('blur');
    }


    /**
     * 注册label标签的编辑事件
     */
    private registerLableSpanContentEditable() {
        if (this.envType !== DesignerEnvType.noCode) {
            return;
        }
        if (!this.element) {
            return;
        }
        const labelSpanEle = this.element.querySelector('.farris-label-text');
        if (!labelSpanEle) {
            return;
        }
        // 启用标签编辑属性
        labelSpanEle.setAttribute('contenteditable', 'true');

        // 监听标签blur事件
        this.addEventListener(labelSpanEle, 'blur', (e) => {
            const newTitle = e.target.innerText;

            if (this.component.title !== newTitle) {

                // 更新控件DOM
                this.component.title = newTitle;

                // 更新模板提示信息
                labelSpanEle.setAttribute('title', newTitle);

                // 更新控件树
                const refreshFormService = this.options.designerHost.getService('RefreshFormService');
                refreshFormService.refreshControlTree.next();

                // 更新属性面板
                this.emit('componentClicked', { componentInstance: this, needUpdatePropertyPanel: true });


                // 控件绑定字段：触发更新schema变更
                if (this.component.binding && this.component.binding.type === FormBindingType.Form) {
                    this.syncSchemaFieldAfterControlTitleChanged(newTitle);
                }

            }

        });
    }
    /** 
     * 修改控件标签后，同步schema字段
     */
    private syncSchemaFieldAfterControlTitleChanged(newTitle: string) {
        // 1、同步viewModel字段增量
        const dgVMService = this.options.designerHost.getService('DesignViewModelService') as DesignViewModelService;
        const dgViewModel = dgVMService.getDgViewModel(this.viewModelId);
        const dgVMField = dgViewModel && dgViewModel.fields.find(f => f.id === this.component.binding.field);
        if (dgVMField) {
            dgViewModel.changeField(dgVMField.id, { name: newTitle });
        }

        // 2、若是零代码表单驱动模板，还需要更改schema里的字段信息
        const formBasicServ = this.options.designerHost.getService('FormBasicService') as FormBasicService;
        if (this.envType === DesignerEnvType.noCode && formBasicServ.driveMode === 'form') {
            const schemaService = this.options.designerHost.getService('SchemaService') as SchemaService;

            // 判断是否为拖拽新增的字段
            const schemaField = schemaService.getFieldByID(dgVMField.id);
            if (schemaField && schemaService.addedFieldsByControlBox.includes(dgVMField.id)) {
                schemaField.name = newTitle;
            }
        }


    }
} 
